سؤال

أنا قادم من خلفية C # حيث تكون هذه الأشياء سوبر سهلة تحاول ترجمة إلى بيثون لمايا.

يجب أن تكون هناك طريقة أفضل للقيام بذلك. في الأساس، أنا أتطلع إلى إنشاء فئة متجهية ستحقق ببساطة X و Y و Z، ولكن سيكون مثاليا إذا أعاد هذا الفصل إلى tuple مع جميع الإحداثيات الثلاثة وإذا كنت تستطيع تحرير قيم هذا tuple من خلال x، خصائص Y و Z، بطريقة أو بأخرى.

هذا هو ما لدي حتى الآن، ولكن هناك يجب كن أفضل طريقة للقيام بذلك من استخدام بيان EXEC، أليس كذلك؟ أنا أكره استخدام بيانات EXEC.

class Vector(object):
    '''Creates a Maya vector/triple, having x, y and z coordinates as float values'''

    def __init__(self, x=0, y=0, z=0):
        self.x, self.y, self.z = x, y, z

    def attrsetter(attr):
        def set_float(self, value):
            setattr(self, attr, float(value))
        return set_float

    for xyz in 'xyz':
        exec("%s = property(fget=attrgetter('_%s'), fset=attrsetter('_%s'))" % (xyz, xyz, xyz))
هل كانت مفيدة؟

المحلول

يحرر: لقد قمت بتعديل الكود مع إجابتي أكثر قليلا من @ unutbu الأصلي لتبسيطها وجعل ما يجري أوضح. في أحدث إصدار، @staticmethodتم القضاء عليها تماما واستبدالها بأبطانة واحدة. تم إعادة تسمية الوظيفة الخارجية وطبقة متداخلة AutoFloatProperties و _AutoFloatProperties لتعكس سلوكهم المتخصص لتحويل وتخزين القيم المعينة كطابع. على الرغم من كل هذا، @ الإجابة المنقحة من @ @

def AutoFloatProperties(*props):
    '''metaclass'''
    class _AutoFloatProperties(type):
        # Inspired by autoprop (http://www.python.org/download/releases/2.2.3/descrintro/#metaclass_examples)
        def __init__(cls, name, bases, cdict):
            super(_AutoFloatProperties, cls).__init__(name, bases, cdict)
            for attr in props:
                def fget(self, _attr='_'+attr): return getattr(self, _attr)
                def fset(self, value, _attr='_'+attr): setattr(self, _attr, float(value))
                setattr(cls, attr, property(fget, fset))
    return _AutoFloatProperties

class Vector(object):
    '''Creates a Maya vector/triple, having x, y and z coordinates as float values'''
    __metaclass__ = AutoFloatProperties('x','y','z')
    def __init__(self, x=0, y=0, z=0):
        self.x, self.y, self.z = x, y, z # values converted to float via properties

if __name__=='__main__':
    v=Vector(1,2,3)
    print(v.x)
    # 1.0
    v.x=4
    print(v.x)
    # 4.0

نصائح أخرى

إذا فهمت سؤالك بشكل صحيح، فأنت تريد شيئا مثل هذا؟

class Vector(object):

    def __init__(self, x=0, y=0, z=0):
        self._x, self._y, self._z = x, y, z

    def setx(self, x): self._x = float(x)
    def sety(self, y): self._y = float(y)        
    def setz(self, z): self._z = float(z)     

    x = property(lambda self: float(self._x), setx)
    y = property(lambda self: float(self._y), sety)
    z = property(lambda self: float(self._z), setz)

هذا يستخدم _x، _y و _z إلى (داخليا) تخزن القيم الواردة ويعرضها عبر استخدام خاصية (مع getters، setters)؛ اختصرت "Getters" باستخدام بيان Lambda.

لاحظ أنه في بيثون سيكون شائع جدا لمعالجة هذه القيم (قل: x، y، z) على الكائن نفسه مباشرة (أعتقد أنك تريد أن تضمن أن يلقي العائم الصريح؟)

قد أكون مخطئا في قراءة سؤالك، لكنني أعتقد أن ما تريد بالفعل من أجلك collections.namedtuple:

>>> from collections import namedtuple
>>> Vector = namedtuple('Vector', 'x y z')
>>> v = Vector(0, 0, 0)
>>> v
Vector(x=0, y=0, z=0)
>>> v.x = 10
>>> v
Vector(x=10, y=0, z=0)
>>> tuple(v)
(10, 0, 0)
>>> v._asdict()
{'x': 10, 'y': 0, 'z': 0}
>>>

هل هذا ينظر عن صحيح؟

للعار، لقد نسيت أن تكون الثلاثي ثابتة. لعن لي لعدم الترقية من بيثون 2.5 لذلك كان بإمكاني اختبار الكود الذي كتبته بالفعل. على أي حال، قد ترغب في شيء مشابه تماما collections.namedtuple, ، باستثناء أشبه افتراضي namedlist. وبعد أو قد ترغب في تجاهل هذه الفكرة بالكامل واستخدام شيء مختلف. النقطة المهمة هي أن هذه الإجابة كانت خاطئة، وأود أن أحذفها، إلا أنني أشعر أنني مضطر إلى الأشخاص الذين رفعوا لي لتصحيح خطأي.

هل هذا ما تبحث عنه؟

class vector(object):
    def __init__(self, x,y,z):
        self.x = x
        self.y = y
        self.z = z

    # overload []
    def __getitem__(self, index):
        data = [self.x,self.y,self.z]
        return data[index]

    # overload set []
    def __setitem__(self, key, item):
        if (key == 0):
            self.x = item
        elif (key == 1):
            self.y = item
        elif (key == 2):
            self.z = item
        #TODO: Default should throw excetion

هذه هي الطريقة الأكثر ساذجة للقيام بذلك. أنا متأكد من أن بعض Python Guru سيأتي ساخرا في الرمز الخاص بي واستبدلها بأبطانة واحدة.

أمثلة على هذا الرمز:

v = vector(1,2,3)
v[1] = 4
v[2] = 5

v.x = 1
v.z= 66

يحرر: حاولت إجابتي السابقة إجراء metaclass المعممي للأجهزة الطينية المعممة التي أعمل بها استخدامها بشكل عام. كما يظهر إجابة @ مارتينيو حل متخصص Vector الطبقة يمكن أن تجعل الأمور أبسط.

إليك فكرة أخرى على طول هذه الخطوط (البساطة المتخصصة على التعقيد المعمم). يستخدم Decorator Decorator (الذي أعتقد أنه أبسط قليلا لفهم من metaclass) و @ فكرة مارتينو بتبسيط getters و setters بالقيم الافتراضية:

def AutoProperties(*props):
    def _AutoProperties(cls):
        for attr in props:
            def getter(self,_attr='_'+attr):
                return getattr(self, _attr)
            def setter(self, value, _attr='_'+attr):
                setattr(self, _attr, float(value))
            setattr(cls,attr,property(getter,setter))
        return cls
    return _AutoProperties

@AutoProperties('x','y','z')
class Vector(object):
    '''Creates a Maya vector/triple, having x, y and z coordinates as float values'''
    def __init__(self, x=0, y=0, z=0):
        self._x, self._y, self._z = map(float,(x, y, z))

الإجابة الأصلية:إليك طريقة لتجنب تكرار رمز لوحة المراجل عند تحديد العديد من الخصائص المشابهة.

لقد حاولت أن أجعل الحل عام بشكل معقول، لذلك قد يكون من الاستخدام للأشخاص في مواقف أخرى بجانب هذا واحد بالذات.

لاستخدامها تحتاج إلى القيام بأشياء:

  1. وضع

        __metaclass__=AutoProperties(('x','y','z'))
    

    في بداية تعريف فصلك. يمكنك سرد (كسلاسل) مثل العديد من السمات (على سبيل المثال x,y,z) كما تتمنا. AutoProperties سوف تحويلها إلى خصائص.

  2. فصلك، على سبيل المثال Vector, ، يحتاج إلى تحديد staticmethods _auto_setter و _auto_getter. وبعد يأخذون حجة واحدة، اسم السمة كسلسلة، وإرجاع وظيفة STERT أو Getter، على التوالي، لهذه السمة.

فكرة استخدام Metaclasses لإعداد العقارات تلقائيا تأتي من مقال Guido Rossum الخصائص والبلاستيك. وبعد هناك يحدد autoprop metaclass مماثلة لما أستخدمه أدناه. الفرق الرئيسي هو ذلك AutoProperties تتوقع أن يحدد المستخدم Getter و STERTER مصانع بدلا من محددة يدويا betters و setters.

def AutoProperties(props):
    class _AutoProperties(type):
        # Inspired by autoprop (http://www.python.org/download/releases/2.2.3/descrintro/)
        def __init__(cls, name, bases, cdict):
            super(_AutoProperties, cls).__init__(name, bases, cdict)
            for attr in props:
                fget=cls._auto_getter(attr)
                fset=cls._auto_setter(attr)
                setattr(cls,attr,property(fget,fset))
    return _AutoProperties

class Vector(object):
    '''Creates a Maya vector/triple, having x, y and z coordinates as float values'''
    __metaclass__=AutoProperties(('x','y','z'))
    def __init__(self, x=0, y=0, z=0):
        # I assume you want the initial values to be converted to floats too.
        self._x, self._y, self._z = map(float,(x, y, z))
    @staticmethod
    def _auto_setter(attr):
        def set_float(self, value):
            setattr(self, '_'+attr, float(value))
        return set_float
    @staticmethod   
    def _auto_getter(attr):
        def get_float(self):
            return getattr(self, '_'+attr)
        return get_float

if __name__=='__main__':
    v=Vector(1,2,3)
    print(v.x)
    # 1.0
    v.x=4
    print(v.x)
    # 4.0

أنا لا أفهم حقا السؤال. لديك متجه يصف نقطة في الفضاء مع 3 إحداثيات. يسمح لك تطبيقك بالفعل بتغيير القيم:

v = Vector()
v.x = 10 # now x is 10

لماذا يجب أن ترجع tuple؟ ماذا تستخدمه ل؟ ومع ذلك، فإن tuple غير ثابت لذلك لا يمكن تعديلها، ولكن يمكنك استخدام قائمة. تغيير الأرقام في تلك القائمة لن تعكس في المتجهات على الرغم من.

إذا كنت بحاجة إلى ضمان أن النوع هو تعويم، فكر المواقع العاصمة:

class C(object):
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

    @x.setter
    def x(self, value):
        print "x set to ", value
        self._x = value

c = C()
c.x = 10

print c.x, c._x

يمكنك بسهولة تمثيل متجه الخاص بك القيام بذلك:

def __repr__(self):
   return "(%.1f, %.1f, %.1f)" % (self.x, self.y, self.z)

عندما تفعل طرق مع __ ... __ يشبه @Override على جافا.

انا افهم ذلك

  1. تريد أن يكون لديك مرشح يحول قيم الإدخال إلى يطفو
  2. أنت لا تريد أن تكتب العقار ثلاث مرات

يمكنك استخدام التعليمات البرمجية التالية:

class Vector(object):
    def __init__(self, x,y,z):
         self._x = x

def mangle(name):
return '_'+name

for name in ['x','y','z']:
    def set_xyz(self, value):
        self.__setattr__(mangle(name), float(value))
    def get_xyz(self):
        return self.__getattribute__(mangle(name))
    prop = property(get_xyz, set_xyz)
    setattr(Vector,name, prop)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top