在类的实例上从Python copy
模块运行deepcopy
时,复制过程的时间随着每次迭代而加倍,即使实例都属于同一个类,因此(至少在我看来)复制所需的时间应该是相同的。你知道吗
我复制的对象使用kwargs
来设置一组属性。它最初还调用了__init__
中的set_dynamic_attributes
方法,以根据某些逻辑配置某些属性,但为了测试这是否导致了速度减慢,我从__init__
中删除了调用,并专门调用了它。你知道吗
以下是违规部分,以及结果:
for a in base_wpn.base_attacks:
t0 = time.time()
a.set_dynamic_attributes()
t1 = time.time()
print('Dyn attributes set time: ' + str(t1-t0))
atk = deepcopy(a)
t2 = time.time()
print('Deepcopy time: ' + str(t2-t1))
结果:
Dyn attributes set time: 0.0
Deepcopy time: 0.01399993896484375
Dyn attributes set time: 0.0
Deepcopy time: 0.03599882125854492
Dyn attributes set time: 0.0
Deepcopy time: 0.04999995231628418
Dyn attributes set time: 0.0
Deepcopy time: 0.09999823570251465
Dyn attributes set time: 0.0
Deepcopy time: 0.011002540588378906
Dyn attributes set time: 0.0
Deepcopy time: 0.021996021270751953
Dyn attributes set time: 0.0
Deepcopy time: 0.0429990291595459
Dyn attributes set time: 0.0
Deepcopy time: 0.08499836921691895
Dyn attributes set time: 0.0
Deepcopy time: 0.17699956893920898
Dyn attributes set time: 0.0
Deepcopy time: 0.32700061798095703
Dyn attributes set time: 0.0
Deepcopy time: 0.6589939594268799
Dyn attributes set time: 0.0
Deepcopy time: 1.4200007915496826
Dyn attributes set time: 0.0
Deepcopy time: 2.466003656387329
Dyn attributes set time: 0.0
Deepcopy time: 5.228000164031982
Dyn attributes set time: 0.0
Deepcopy time: 10.528998374938965
如果有帮助的话(我知道如果没有更多的代码和大量的对象引用,它是不可复制的),下面是构建实例的对象定义:
class Attack():
def __init__(self, name, weapon, **kwargs):
self.name = name
self.weapon = weapon
self.skill = [self.weapon.skill]
self.attack_mod = self.weapon.attack_mod
self.parry_mod = -self.weapon.parry_mod #Modifier to OPPONENT'S parry chance
self.stamina = self.weapon.stamina
self.main_shape = None
self.striker = None
self.hands = 1
self.damage_type = 'b'
self.base_ap = 0
self.hand = True
self.added_mass = self.weapon.added_mass
self.length = 0 #Used to add or subtract from base weapon length got added/reduced reach
self.side_restrict = True #Determines if the attack can only hit one side of the enemy (i.e. hook from R hand only hitting left side)
self.restricted_locs = [] #Locations that can never be targeted with this attack (i.e. foot with uppercut)
self.allowed_angles_r = [] #Angles that are allowed as an index of angles (0 = N-> S, 7 = NW -> SE, 8 = thrust) (i.e. N->S with an uppercut)
self.allowed_angles_l = [] #Angles that are allowed as an index of angles (0 = N-> S, 7 = NW -> SE, 8 = thrust) (i.e. N->S with an uppercut)
self.main_area = 0
self.mech_adv = 0
self.force_scalar = 1 #Used to adjust force/damage for the attack
for k in kwargs:
for key in self.__dict__:
if k == key:
self.__dict__.update(kwargs)
#self.set_dynamic_attributes()
def set_dynamic_attributes(self):
for t in self.damage_type:
if t == 'b':
if self.striker == 'main':
shape = self.weapon.main_shape
else:
shape = 'round'
if shape == 'wedge':
self.main_area = self.weapon.main_length * self.weapon.avg_main_width
self.mech_adv = self.weapon.main_depth / self.weapon.main_width
elif shape == 'round':
#Using Hertz's result, but using fixed f value built off of added_mass + fist mass (.86) and v of 40 f/s2 and fixed p_ratio for target
#Equation: https://www.quora.com/Is-the-area-of-contact-between-a-cylinder-and-a-flat-surface-infinitely-small-Is-it-a-point
if self.striker == 'main':
material = self.weapon.main_material
width = self.weapon.main_width
length = self.weapon.main_length
elif self.striker == 'shaft':
material == self.weapon.shaft_material
width = 1
length = self.weapon.shaft_length
else:
material = self.weapon.accent_material
width = length = 1
e_calc = ((1-(material.p_ratio * material.p_ratio))/(material.elasticity*10))+((1-(.4*.4))/5)
self.main_area = sqrt((4*((.86 + self.added_mass)*40)*width)/(3.514*(e_calc)*min(length, 8)))
elif self.main_shape == 'flat':
self.main_area = min(self.weapon.main_length,8) * min(self.weapon.main_width,8)
elif t == 's':
if self.main_shape == 'blade':
self.main_area = min(self.weapon.main_length, 8) * self.weapon.avg_main_width
self.mech_adv = self.weapon.main_depth / self.weapon.main_width
elif self.main_shape == 'de blade':
self.main_area = min(self.weapon.main_length, 8) * self.weapon.avg_main_width
self.mech_adv = (self.weapon.main_depth/2) / self.weapon.main_width
elif t == 'p':
if self.striker == 'main':
shape = self.weapon.main_shape
length = self.weapon.main_length
depth = self.weapon.main_depth
width = self.weapon.main_width
else:
shape = 'point'
if self.striker == 'shaft':
length = min(self.weapon.shaft_length, 8)
depth = width = 1
else:
length = depth = width = 1
if shape in ['point', 'blade']:
wedge1 = length / width
wedge2 = width / depth
#Double each (since there are two wedges per side) and multiply for full MA of tip
self.mech_adv = (wedge1*2)*(wedge2*2)
self.main_area = depth * length * width
else:
if self.main_shape == 'hook':
wedge1 = self.weapon.main_length / self.weapon.main_width
wedge2 = self.weapon.main_width / self.weapon.main_depth
#Double each (since there are two wedges per side) and multiply for full MA of tip
self.mech_adv = (wedge1*2)*(wedge2*2)
self.main_area = self.weapon.main_depth * self.weapon.main_width
if self.damage_type in ['s','b']:
self.stamina += self.weapon.weight + int(self.weapon.weight*self.weapon.axis_vs_com)
self.base_ap += min(self.weapon.weight/10, (self.weapon.weight * 10)/self.weapon.axis_vs_com)
self.added_mass = self.weapon.weight / self.weapon.com_perc
self.attack_mod += (20 - ((self.weapon.weight*10) * self.weapon.com_perc))
self.parry_mod -= ((self.weapon.weight*10) * self.weapon.com_perc)
if self.weapon.main_num > 1:
self.attack_mod += self.weapon.main_num * 5
self.parry_mod -= self.weapon.main_num * 20
else:
self.stamina += self.weapon.weight/2
self.base_ap += self.weapon.weight * 5
self.added_mass = self.weapon.weight/10
if self.damage_type == 'p':
self.attack_mod -= self.weapon.weight/10
self.parry_mod -= self.weapon.weight * 5
else:
self.attack_mod += -5 + (self.weapon.main_num * 5)
self.parry_mod -= self.weapon.main_num * 20
需要更多的代码。以下是武器类(攻击引用)和材料类(武器引用)的代码:
class Weapon:
def __init__(self, **kwargs):
self.name = ''
self.shafted = False #Used to determine if wpn has a shaft
self.allowed_main_materials = [] # List of materials applicable for the main surface. Young's modulus prevents copper and bronze swords longer than 24", for example
self.main_material = m_steel #Damage component (blade, head, etc) material
self.shaft_material = m_wood
self.grip_material = m_leather
self.accent_material = m_steel
self.attack_mod = 0
self.parry_mod = 0 #Mod to weilder's ability to parry with weapon
self.b_striker = 'accent' #Striking surface for damage type. Can be main, shaft, accent, or none
self.s_striker = 'main'
self.p_striker = 'main'
self.t_striker = 'none'
self.hands = [1] #List can include 0,1,2
self.quality = 'Average'
self.base_name = 'Weapon'
self.bname_variants = [] #A list of variant names for the weapon
self.skill = None #This is the default skill used for the weapon. String
self.length = 1
self.shaft_length = 0 #Also used as tethers for flail and whip like weapons
self.shaft_diameter = 0
self.shaft_num = 0
self.pre_load = False #Used to account for weapons that can be preloaded with velocity, like flails or staves
self.avg_main_width = 1 #1.25 average longsword
self.main_width = 1 #Absolute width at widest point
self.avg_main_depth = .1 #.14 is average for a sword blade
self.main_depth = .2 #Absolute depth at deepest point
self.main_shape = 'de blade' #Acceptable values: de blade, blade, point, wedge, round, flat, hook
self.main_num = 1 #Number of main attack surfaces, mostly used for flails/flogs
self.accent_cuin = 1 #Cubic inches of accent material, such as the crossguard and pommel on a sword
self.main_com = .5 #Center of mass for the main weapon component
self.main_loc = .1 #Location along the total length for the main weapon component
self.accent_loc = .05 #Location along the total length for the accent component
self.grip_loc = .03 #location along the total length for the grip
self.main_weight = 0
self.shaft_weight = 0
self.accent_weight = 0
self.grip_weight = 0
self.weight = 0
self.main_length = 0
self.added_mass = 0
self.damage_type = 'b'
self.stamina = 0
#Maximums; used to procedurally gen weapons
self.main_len_range = (0,0) #Tuple containing min and max range for acceptable lengths
self.main_depth_range = (0,0)
self.main_avg_depth_range = (0,0)
self.main_width_range = (0,0)
self.main_avg_width_range = (0,0)
self.length_range = (0,0)
self.shaft_length_range = (0,0)
self.shaft_diameter_range = (0,0)
self.max_main_num = 1
self.max_shaft_num = 1
self.main_only_com = 0
self.shaft_only_com = 0
self.accent_only_com = 0
self.com = 0 #Center of mass for the whole weapon
self.com_perc = 0 #com as a percentage
self.axis_vs_com = 0 #Shows COM relative to grip location (axis for swings). Used to determine AP/stamina costs.
self.main_hits = 0
self.staff_hits = 0
self.accent_hits = 0
self.min_pwr_1h = 0 #1 pwr = 1 ft/lb; accelleration = 40 f/s2; weight of average hand = .86 lb
self.min_pwr_2h = 0 #1 pwr = 1.5 ft/lb; accelleration = 40 f/s2; weight of average hand = .86 lb
self.solidness = 1 #Used in damage calc
self.sharpness = 1
self.pointedness = 1
self.base_attacks = []
self.attacks = []
self.base_maneuvers = []
self.maneuvers = []
self.guards = []
self.cost = 0
self.normality = 1
for k in kwargs:
for key in self.__dict__:
if k == key:
self.__dict__.update(kwargs)
self.set_dynamic_attributes()
def set_dynamic_attributes(self):
#Determine which variant name to use
if len(self.bname_variants) > 1:
n_idx = roll_dice(1, len(self.bname_variants))
n_idx -= 1
self.base_name = self.bname_variants[n_idx]
#Name weapon using quality and material, if applicable
if self.main_material is not m_tissue:
if self.quality != 'Average':
self.name = self.quality + ' ' + self.main_material.name + ' ' + self.base_name
else:
self.name = self.main_material.name + ' ' + self.base_name
else:
self.name = self.base_name
self.attack_mod = 20 * quality_dict.get(self.quality)
self.parry_mod = 20 * quality_dict.get(self.quality)
self.main_weight = ((self.main_length * self.avg_main_depth * self.avg_main_width)*self.main_num) * (self.main_material.density * .03)
self.shaft_weight = (self.shaft_length * self.shaft_diameter * (self.shaft_material.density * .03)) * self.shaft_num
self.accent_weight = self.accent_cuin * (self.accent_material.density * .03)
self.grip_weight = self.grip_material.density * (.3 * max(self.hands))
self.weight = self.main_weight + self.shaft_weight + self.accent_weight
self.main_only_com = ((self.main_length*self.main_com)+(self.main_loc*self.length))*self.main_weight
self.shaft_only_com = (self.shaft_length*.5)*self.shaft_weight
self.accent_only_com = (self.accent_loc*self.length)*self.accent_weight
self.com = (self.main_only_com + self.shaft_only_com + self.accent_only_com)/self.weight #Center of mass for the whole weapon
self.com_perc = self.com / self.length #com as a percentage
self.axis_vs_com = self.com_perc - self.grip_loc #Shows COM relative to grip location (axis for swings). Used to determine AP/stamina costs.
self.main_hits = (self.main_material.elasticity * 1450000) * (self.main_weight/(self.main_material.density*.03)) * self.main_material.toughness
self.min_pwr_1h = ((self.added_mass + .86) * 40)/1 #1 pwr = 1 ft/lb/s; accelleration = 40 f/s2; weight of average hand = .86 lb
self.min_pwr_2h = ((self.added_mass + 1.72) * 40)/1.5 #1 pwr = 1.5 ft/lb/s; accelleration = 40 f/s2; weight of average hand = .86 lb
if self.main_material.elasticity < 1: self.solidness = self.main_material.elasticity
if self.main_material.hardness < 1:
self.sharpness = self.main_material.hardness
self.pointedness = self.main_material.hardness
else:
self.sharpness = sqrt(self.main_material.hardness)
self.pointedness = self.main_material.hardness
#Damage calc = ((((added_mass + fist mass) * velocity) / main_area) * mech_adv) * sharpness or hardness or pointedness
main_materials_cost = self.main_material.cost * self.main_weight
shaft_materials_cost = self.shaft_material.cost * self.shaft_weight
grip_materials_cost = self.grip_material.cost * self.grip_weight
accent_materials_cost = self.accent_material.cost * self.accent_weight
#Crafting costs. 1 day skilled labor = ~5 material cost
main_crafting_cost = self.main_material.craft_diff * self.main_weight
shaft_crafting_cost = self.shaft_material.craft_diff * self.shaft_weight
grip_crafting_cost = self.grip_material.craft_diff * self.grip_weight
accent_crafting_cost = self.accent_material.craft_diff * self.accent_weight
self.cost = main_crafting_cost + main_materials_cost + shaft_crafting_cost + shaft_materials_cost + grip_crafting_cost + grip_materials_cost + accent_crafting_cost + accent_materials_cost
self.normality = self.main_material.normality * self.shaft_material.normality * self.grip_material.normality * self.accent_material.normality
class Material():
_allMaterials = []
def __init__(self, **kwargs):
#Below is to create a list of instances of this class
self._allMaterials.append(self)
self.name = None
#Goal: Hardness and elasticity set the hits for the material, toughness then scales them up or down.
self.hardness = 1 #Scalar. 1 = ~7 Brinell, roughly very hard wood. Copper 85, Bronze 180, Iron 300, Steel 400-600
self.elasticity = 1 #Scalar. Basically resistance to deformation. 1 = Wood, average modulus of elasticity ~10 GPa. Bone 18, Gold 79, Copper 100, Bronze 120, Iron 210, Steel 200
self.toughness = 1 #Scalar. Resistance to breaking when deformed. 1 = Wood, very non-brittle. 10 = Gold, very malliable. .5 = Steel, somewhat brittle. 0.1 = stone
self.p_ratio = .5 #Poisson's ratio. Non-scaled, use actual values
self.normality = 1 #Scalar. How rare the material is. 1 = Iron, very common. Gold is 4 million times rarer than Iron, but probably it will be ~.01 in game
self.cost = 1 #Scalar. Raw cost of the material (taking into account refining costs). 1 = Wood, cheap $0.23/lb. 10 = Copper, $2.50/lb. 82,000 = Pure Gold
self.craft_diff = 1 #Scalar. Difficulty of crafting. 1 = 1 day of crafting per lb of finished material. Cost of 1 day of a craftsman = 5
# For metals, hardness modifies it. Hardened Steel takes 5 days to craft 1 pound of weaponry.
self.density = 1 #Scalar. Relative density per cubic inch. 1 = Wood, .03 lb/in3. Copper = .32, Silver = .38, Gold = .7, Iron = .28, Bronze = .3, Steel = .28
for key in self.__dict__:
for k in kwargs:
if k == key:
self.__dict__.update(kwargs)
self.set_dynamic_attr()
def set_dynamic_attr(self):
if self.craft_diff == 0:
self.craft_diff = .078 * self.hardness
self.craft_diff = round(self.craft_diff, 2)
解决了这个问题;正如用户10987432所怀疑的,它正在创建树上所有对象的副本。我通过移除构造器中的武器引用并将每个属性作为kwarg(ugh)传递来修复它。使一个非常丑陋的4线电话,但它的工作和速度快。一旦它够烦人的话,我就看看能否缩短它;因为现在我只能复制/粘贴,只更改相关字段。你知道吗
Edit:我更清楚地解决了这个问题,将单个攻击设置为攻击类的所有子类,并为每个参与者创建它们的实例。我不知道为什么我最初没有这样做,我已经做了机动,但现在它更容易阅读和调试。再次感谢大家的帮助。你知道吗
相关问题 更多 >
编程相关推荐