Атрибут bucket_name
является атрибутом instance , поэтому bucket_path
не может зависеть от bucket_name
и одновременно быть атрибутом класса.
Оба должны быть либо атрибутами класса, либо атрибутами экземпляра.
Атрибуты экземпляра
Если оба должны быть атрибутами экземпляра, тогда метакласс не нужен, достаточно property
.
class M(object):
def __init__(self, bucket_name):
self.bucket_name = bucket_name
@property
def bucket_path(self):
return "{}_created".format(self.bucket_name)
m = M('foo')
print(m.bucket_path) # foo_created
Атрибуты класса
Если оба должны быть атрибутами класса, то вы хотите определить свойство, но для класса.Хотя вы можете определить декоратор класса для реализации свойств класса , этого можно достичь и с помощью метакласса.
class MyMeta(type):
def __new__(cls, name, bases, namespace):
if 'bucket_name' not in namespace:
raise TypeError("class must have 'bucket_name'")
# This is meant to also delegate the instance attribute to the class property
namespace['bucket_path'] = property(lambda self: type(self).bucket_path)
return super(MyMeta, cls).__new__(cls, name, bases, namespace)
@property
def bucket_path(cls):
return "{}_created".format(cls.bucket_name)
class M(object):
__metaclass__ = MyMeta
bucket_name = 'foo'
print(M.bucket_path) # foo_created
print(M().bucket_path) # foo_created